﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;

namespace LaunchPad.Core.Controls.Tracks
{
    /// <summary>
    /// Interaction logic for EffectSliderControl.xaml
    /// </summary>
    public partial class EffectSliderControl : AudioTimeControlBase
    {
        public static readonly DependencyProperty EventsProperty = DependencyProperty.RegisterAttached(
            "Events", typeof (ObservableCollection<TrackEvent>), typeof (AudioTimeControlBase),
            new FrameworkPropertyMetadata(null, OnEventsChanged));

        public EffectSliderControl()
        {
            InitializeComponent();
            SizeChanged += EffectSliderControlSizeChanged;
            PositionChanged += EffectSliderControlPositionChanged;
        }

        public ObservableCollection<TrackEvent> Events
        {
            get { return (ObservableCollection<TrackEvent>) GetValue(EventsProperty); }
            set { SetValue(EventsProperty, value); }
        }

        private IEnumerable<CueControl> CueControls
        {
            get { return cueCanvas.Children.OfType<CueControl>(); }
        }

        private static void OnEventsChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            var control = sender as EffectSliderControl;
            if (control != null)
                control.OnEventsChanged(e);
        }

        private void EffectSliderControlPositionChanged(object sender, PlaybackPositionEventArgs e)
        {
            playbackControl.Position = e.Position;
        }

        private void EffectSliderControlSizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (e.HeightChanged)
            {
                playbackControl.Height = e.NewSize.Height;
                foreach (CueControl cue in CueControls)
                    cue.Height = e.NewSize.Height;
            }
        }


        protected void OnEventsChanged(DependencyPropertyChangedEventArgs e)
        {
            if (e.OldValue != null)
            {
                ((ObservableCollection<TrackEvent>) e.OldValue).CollectionChanged -=
                    EventsCollectionChanged;
            }

            if (e.NewValue != null)
            {
                ((ObservableCollection<TrackEvent>) e.NewValue).CollectionChanged +=
                    EventsCollectionChanged;

                foreach (EffectTrackEvent ev in e.NewValue as ObservableCollection<TrackEvent>)
                {
                    AddEvent(ev);
                }
            }
        }

        private void EventsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null)
            {
                foreach (EffectTrackEvent ete in e.NewItems)
                    AddEvent(ete);
            }

            if (e.OldItems != null)
            {
                foreach (EffectTrackEvent ete in e.OldItems)
                    RemoveEvent(ete);
            }
        }

        public void AddEvent(EffectTrackEvent e)
        {
            var timeBinding = new Binding("Start") {Converter = TimePositionConverter, Mode = BindingMode.TwoWay};

            var descBinding = new Binding("Description");

            var cue = new CueControl();
            cue.SetBinding(Canvas.LeftProperty, timeBinding);
            cue.SetBinding(ToolTipProperty, descBinding);
            cue.DataContext = e;
            e.PropertyChanged += EventPropertyChanged;

            cue.MoveBeginning += CueControlMoveBeginning;
            cue.MoveComplete += CueControlMoveComplete;
            cue.PositionChanged += CueControlPositionChanged;

            cueCanvas.Children.Add(cue);

            cue.Height = ActualHeight;

            UpdateCueControl(cue, e);
        }

        private void UpdateCueControl(CueControl cue, EffectTrackEvent e)
        {
            cue.LeadInLength = ConvertFromTime(e.LeadIn);
            cue.LeadOutLength = ConvertFromTime(e.LeadOut);
            cue.Width = cue.LeadInLength + cue.LeadOutLength;
            cue.UpdateBindings();
        }

        private void UpdateCueControls()
        {
            foreach (CueControl cue in CueControls)
                UpdateCueControl(cue, cue.DataContext as EffectTrackEvent);
        }

        protected override void OnTrackChanged(DependencyPropertyChangedEventArgs e)
        {
            UpdateCueControls();
        }

        protected override void OnZoomFactorChanged(DependencyPropertyChangedEventArgs e)
        {
            UpdateCueControls();
        }

        private void EventPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            var ete = sender as EffectTrackEvent;
            CueControl cue = CueControls.Single(c => c.DataContext == sender);

            switch (e.PropertyName)
            {
                case "LeadIn":
                case "LeadOut":
                    UpdateCueControl(cue, ete);
                    break;
            }
        }

        private void CueControlMoveBeginning(object sender, EventArgs e)
        {
            OnBeginCueHelperMove();
        }

        private void CueControlMoveComplete(object sender, EventArgs e)
        {
            OnEndCueHelperMove();
        }

        private void CueControlPositionChanged(object sender, EventArgs e)
        {
            var cue = sender as CueControl;
            if (cue != null)
            {
                var ete = cue.DataContext as EffectTrackEvent;
                if (ete != null) 
                    OnCueHelperMove(ete.Time);
            }
        }

        public void RemoveEvent(EffectTrackEvent e)
        {
            CueControl cue = CueControls.FirstOrDefault(c => c.DataContext == e);

            if (cue != null)
            {
                cue.MoveBeginning -= CueControlMoveBeginning;
                cue.MoveComplete -= CueControlMoveComplete;
                cue.PositionChanged -= CueControlPositionChanged;
                cueCanvas.Children.Remove(cue);
            }
        }

        private void ClearEventsMenuItemClick(object sender, RoutedEventArgs e)
        {
            if (MessageBox.Show("Delete all events?", "LaunchPad", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
            {
                var effect = (DataContext as EffectTrack);
                if (effect != null) effect.Timeline.Clear();
            }
        }

        private void PlaybackControlPositionChanged(object sender, EventArgs e)
        {

            //OnPlaybackPositionChanged(this, 
            //    new PlaybackPositionEventArgs(ConvertFromPosition(playbackControl.Position)));
        }

        private void PlaybackControlMouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
        }

        #region DnD

        //private Point _mouseStartPoint;

        //private void cueCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        //{
        //    switch (e.ClickCount)
        //    {
        //        case 1:
        //            {
        //                cueCanvas.Focus();
        //                e.Handled = true;
        //                _mouseStartPoint = Mouse.GetPosition(null);
        //                break;
        //            }
        //        case 2:
        //            {
        //                double pos = Mouse.GetPosition(cueCanvas).X;
        //                TimeSpan time = ConvertFromPosition(pos);
        //                AddNewEvent(time);
        //                e.Handled = true;
        //                break;
        //            }
        //    }
        //}

        //private void cueCanvas_MouseMove(object sender, MouseEventArgs e)
        //{
        //    if (e.LeftButton == MouseButtonState.Pressed)
        //    {
        //        Point mousePos = e.GetPosition(null);
        //        Vector diff = _mouseStartPoint - mousePos;

        //        bool minDragMet = 
        //            Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
        //            Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance;

        //        if (e.LeftButton == MouseButtonState.Pressed && minDragMet)
        //        {
        //            // Initialize the drag & drop operation
        //            DataObject dragData = new DataObject("effectFormat", DataContext);
        //            DragDrop.DoDragDrop(this, dragData, DragDropEffects.Move);
        //        } 
        //    }
        //}

        //private void EffectSliderControl_DragEnter(object sender, DragEventArgs e)
        //{
        //    if (e.Data.GetDataPresent("nodeFormat"))
        //        e.Handled = true;
        //    else
        //        e.Effects = DragDropEffects.None;
        //}

        //private void EffectSliderControl_DragOver(object sender, DragEventArgs e)
        //{
        //    if (e.Data.GetDataPresent("nodeFormat"))
        //        e.Handled = true;
        //    else
        //        e.Effects = DragDropEffects.None;
        //}

        //private void EffectSliderControl_Drop(object sender, DragEventArgs e)
        //{
        //    if (e.Data.GetDataPresent("nodeFormat"))
        //    {
        //        Node node = e.Data.GetData("nodeFormat") as Node;

        //        Node originalNode = (DataContext as Effect).Node;

        //        if (node != originalNode)
        //        {
        //            if (node.Effects.Count < Node.MaxEffects)
        //            {
        //                if (originalNode != null)
        //                    originalNode.Effects.Remove(DataContext as Effect);

        //                node.Effects.Add(DataContext as Effect);
        //            }
        //            else MessageBox.Show(
        //                string.Format("Nodes cannot support more than {0} effects", Node.MaxEffects), "LaunchPad");
        //        }

        //        e.Handled = true;
        //    }
        //}

        #endregion
    }
}